/*
    连接相关类的定义：连接类、连接管理类
    1. 连接类：在muduo库所提供连接的基础上进行二次封装，进行细粒度化管理，提供信道的概念。
        一个连接会管理一批信道，所以说信道是以连接为单位进行管理的
        属性：具有信道的所有属性、管理信道的句柄
        方法：打开信道、删除信道、获取信道
    2. 连接管理类：对连接对象的管理
        属性：连接对象映射表<muduo::net::TcpConnectionPtr, 连接对象>
        方法：添加连接、删除连接、获取连接
*/

#pragma once
#include "channel.hpp"


namespace mq
{
    class Connection
    {
    public:
        using ConnectionPtr = std::shared_ptr<Connection>;

    public:
        Connection(const ConsumerManager::ConsumerManagerPtr& consumer_manager_ptr, const muduo::net::TcpConnectionPtr& conn_ptr, const ProtobufCodecPtr& codec_ptr, 
            const VirtualHost::VirtualHostPtr& virtual_host_ptr, const ThreadPool::ThreadPoolPtr& thread_pool_ptr)
            : _consumer_manager_ptr(consumer_manager_ptr), _conn_ptr(conn_ptr), _codec_ptr(codec_ptr), _virtual_host_ptr(virtual_host_ptr), 
            _thread_pool_ptr(thread_pool_ptr), _channel_manager_ptr(std::make_shared<ChannelManager>())
        {}

        // 打开信道
        void openChannel(const OpenChannelRequestPtr &req)
        {
            bool ret = _channel_manager_ptr->openChannel(req->channel_id(), _consumer_manager_ptr, _conn_ptr, _codec_ptr, _virtual_host_ptr, _thread_pool_ptr);
            responseHandler(ret, req->request_id(), req->channel_id());
        }

        // 关闭信道
        void closeChannel(const CloseChannelRequestPtr &req)
        {
            _channel_manager_ptr->closeChannel(req->channel_id());
            responseHandler(true, req->request_id(), req->channel_id());
        }

        // 获取指定信道
        Channel::ChannelPtr getChannel(const std::string id)
        {
            return _channel_manager_ptr->getChannel(id);
        }

    private:
        // 响应处理函数 
        void responseHandler(bool success, const std::string& response_id, const std::string& channel_id)
        {
            // 构建响应并从指定channel发送
            CommonResponse response;
            response.set_success(success);
            response.set_response_id(response_id);
            response.set_channel_id(channel_id);
            _codec_ptr->send(_conn_ptr, response);
        }

    private:
        ConsumerManager::ConsumerManagerPtr _consumer_manager_ptr; // 消费者管理句柄
        muduo::net::TcpConnectionPtr _conn_ptr;                    // 连接句柄
        ProtobufCodecPtr _codec_ptr;                                 // 序列化协议句柄
        VirtualHost::VirtualHostPtr _virtual_host_ptr;             // 虚拟机句柄
        ThreadPool::ThreadPoolPtr _thread_pool_ptr;                // 线程池句柄
        ChannelManager::ChannelManagerPtr _channel_manager_ptr;    // 信道管理句柄
    };

    // 连接管理类
    class ConnectionManager
    {
    public:
        using ConnectionManagerPtr = std::shared_ptr<ConnectionManager>;

    public:
        ConnectionManager()
        {}

        // 添加连接
        void newConnection(const ConsumerManager::ConsumerManagerPtr& consumer_manager_ptr, const muduo::net::TcpConnectionPtr& tcp_conn_ptr, 
            const ProtobufCodecPtr& codec_ptr, const VirtualHost::VirtualHostPtr& virtual_host_ptr, const ThreadPool::ThreadPoolPtr& thread_pool_ptr)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it =_conns.find(tcp_conn_ptr);
            if(it != _conns.end())
                return;
            Connection::ConnectionPtr self_conn_ptr = std::make_shared<Connection>(consumer_manager_ptr, tcp_conn_ptr, codec_ptr, virtual_host_ptr, thread_pool_ptr);
            _conns.insert(std::make_pair(tcp_conn_ptr, self_conn_ptr));
        }

        // 删除连接
        void delConnection(const muduo::net::TcpConnectionPtr& conn_ptr)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _conns.erase(conn_ptr);
        }

        // 获取连接
        Connection::ConnectionPtr getConnection(const muduo::net::TcpConnectionPtr& conn_ptr)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter = _conns.find(conn_ptr);
            if (iter != _conns.end())
                return iter->second;
            return nullptr;
        }
    
    private:
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ConnectionPtr> _conns;
        std::mutex _mutex;
    };
}